<script setup lang="ts" name="menu-management">
import { getMenuMgtList, menuMgtDel, menuMgtSort } from '@fl/api/exploit-setting'
import ButtonItem from '@fl/components/button-item.vue'
import { replaceElIdx } from '@fl/utils/index'
import { ElCard, ElTable, ElTableColumn } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import Sortable from 'sortablejs'
import { onMounted, ref } from 'vue'

import AddMenu from './component/add-menu.vue'

const detail = reactive<any>({})
const activeRow = ref<any>([])
const show = ref(false)
const addRef = ref()
const tableData = ref<any>([])
const expandRowKeys = ref<string[]>([])
const loading = ref<boolean>(false)
const tableRef = ref(null)

const btns = [
    {
        label: '编辑',
        text: true,
        value: 'edit',
    },
    {
        label: '删除',
        text: true,
        value: 'delete',
    },
]

function load(row: any, _treeNode: unknown, resolve: ((date: any) => void) | undefined) {
    if (row.childList.length)
        resolve?.(row.childList)
}

function rowClassName({ row }: { row: any }) {
    // 给第一级行 设置类名 用于sortable的draggable字段，指定类可排序
    if (row?.isFirst)
        return 'sortItem'

    return ''
}

function handleExpand(row: any, expanded: boolean) {
    // 一级行实现手风琴
    if (row?.isFirst)
        expandRowKeys.value = expanded ? [row.id] : []
}

function rowDrop() {
    const tbody = document.querySelector('.el-table__body-wrapper tbody') as HTMLElement
    Sortable.create(tbody, {
        draggable: '.sortItem', // 拥有sortItem类名的行才能排序
        onEnd(evt: any) {
            // newDraggableIndex , oldDraggableIndex 是可拖拽元素的下标,更具这两个下表获取id，传递给后端排序，重新获取数据
            doSort(evt)
        },
        onStart() {
            // 拖拽开始收起所有张开的行
            // expandRowKeys.value = []
        },
        setData(/** DataTransfer */dataTransfer, /** HTMLElement */dragEl: any) {
            const text = dragEl.textContent.split(' ')[1]
            activeRow.value = JSON.parse(`{${getStr(text)}}`)
            dataTransfer.setData('Text', dragEl.textContent) // `dataTransfer` object of HTML5 DragEvent
        },
    })
}

function getStr(str: string) {
    const regex = /{([^}]+)}/
    const match = str.match(regex)
    return match ? match[1] : null
}

function doSort(evt: any) {
    const { newDraggableIndex, oldDraggableIndex } = evt
    const target: any = tableData.value.find((v: any) => v.id === activeRow.value.parentId).childList

    const params = replaceElIdx(target, oldDraggableIndex, newDraggableIndex)
    params.forEach((v: any, idx: number) => {
        v.sort = idx
    })
    menuMgtSort(params).then((res: any) => {
        if (res.code === 200) {
            getData()
            ElMessage.success('操作成功')
        }
        else { ElMessage({ message: res.msg, type: 'error' }) }
    })
}

function doAdd() {
    show.value = true
    detail.value = null
}

function doAction(item: any, row: any) {
    switch (item.value) {
        case 'edit':
            show.value = true
            detail.value = row
            break
        case 'delete':
            doDel(row.id)
            break
        default:
            break
    }
}

function doDel(id: any) {
    menuMgtDel({ id }).then((res: any) => {
        if (res.code === 200) {
            getData()
            ElMessage.success('操作成功')
        }
        else { ElMessage({ message: res.msg, type: 'error' }) }
    }).catch((err) => {
        const message = err?.response?.data?.message || err
        ElMessage({ message, type: 'error' })
    })
}

async function getData() {
    tableData.value = []

    loading.value = true
    getMenuMgtList({
        appCode: '1003', // 默认写死
    }).then((res: any) => {
        const target: any = res ?? []
        if (target.length) {
            target.forEach((v: any) => {
                const hasChildren = v.childList.length
                v.hasChildren = hasChildren
                if (hasChildren) {
                    // 遍历数据手动添加 isFirst 字段，用于添加类名，用于排序，和设置expand-row-keys （展开行的key）
                    v.childList.forEach((child: any) => {
                        child.isFirst = true
                    })
                }
            })
        }
        tableData.value = cloneDeep(target)
    }).catch((err) => {
        const message = err?.response?.data?.message || err
        ElMessage({ message, type: 'error' })
    }).finally(() => {
        loading.value = false
    })
}
getData()

onMounted(() => {
    // 拖拽处理
    document.body.ondrop = function (event) {
        event.preventDefault()
        event.stopPropagation()
    }
    // 拖拽功能与配置
    rowDrop()
})
</script>

<template>
    <ElCard mb-20>
        <div class="mb-20">
            <ElButton type="primary"
                      @click="doAdd"
            >
                + 新增菜单
            </ElButton>
        </div>

        <ElTable ref="tableRef"
                 v-loading="loading"
                 :data="tableData"
                 style="width: 100%"
                 row-key="id"
                 :load="load"
                 lazy
                 border
                 :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
                 :expand-row-keys="expandRowKeys"
                 :row-class-name="rowClassName"
                 @expand-change="handleExpand"
        >
            <ElTableColumn label="菜单">
                <template #default="scope">
                    {{ scope.row.menuName }}
                    <span style="display: none;">
                        {{ JSON.stringify({ id: scope.row.id, parentId: scope.row.parentId }) }}
                    </span>
                </template>
            </ElTableColumn>

            <ElTableColumn prop="appMenuName"
                           label="关联应用"
            />

            <ElTableColumn prop="createTime"
                           label="创建时间"
            />

            <ElTableColumn prop="updateTime"
                           label="修改时间"
            />

            <ElTableColumn label="操作">
                <template #default="scope">
                    <ButtonItem :btns="btns"
                                @btn-click="doAction($event, scope.row)"
                    />
                </template>
            </ElTableColumn>
        </ElTable>
    </ElCard>

    <AddMenu ref="addRef"
             v-model="show"
             :data="detail"
             template
             @confirm="getData"
    />
</template>
